/*
 * Copyright 2008 Google Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package com.google.gwt.widgetideas.client;

import com.google.gwt.user.client.ui.HasText;
import com.google.gwt.user.client.ui.SuggestOracle;

/**
 * This is a stubbed out RPC {@link SuggestOracleOverride} for use by
 * {@link SuggestBoxOverride} instances backed by server side data.
 * 
 * This oracle allows only one request to be sent out at a time. The reason is
 * because we do not want to accidently create a denial of service attack on our
 * own servers, and so want to limit the number of RPC requests generated by
 * someone rapidly typing in a suggest box.
 */

public abstract class RPCSuggestOracle extends SuggestOracle {
  private HasText suggester;
  private Callback currentCallback;
  private Request pendingRequest;
  private Callback pendingCallback;

  private Callback wrappedCallback = new Callback() {

    public void onSuggestionsReady(Request request, Response response) {
      if (suggester.getText().equals(request.getQuery())) {
        currentCallback.onSuggestionsReady(request, response);
        pendingRequest = null;
        pendingCallback = null;
      }
      currentCallback = null;
      if (pendingCallback != null) {
        requestSuggestions(pendingRequest, pendingCallback);
        pendingRequest = null;
        pendingCallback = null;
      }
    }

  };

  public RPCSuggestOracle() {
  }

  @Override
  public final void requestSuggestions(Request request, Callback callback) {
    assert suggester != null : "Must call setSuggestWidget before requesting suggestions";
    if (currentCallback == null) {
      currentCallback = callback;
      sendRequest(request, wrappedCallback);
    } else {
      pendingRequest = request;
      pendingCallback = callback;
    }
  }

  /**
   * Physically send the request over the wire.
   * 
   * @param request the request
   * @param callback the call back
   */
  public abstract void sendRequest(Request request, Callback callback);

  /**
   * Sets the widget who is using the {@link SuggestOracleOverride}. Usually it
   * is a {@link SuggestBoxOverride}, however to support the use of custom
   * suggest widgets, any widget that implements HasText can be passed in here.
   * 
   * @param suggestBox the widget calling to this oracle.
   */
  public void setSuggestWidget(HasText suggestBox) {
    suggester = suggestBox;
  }
}
